package com.vip.workflow.service.impl;

import com.vip.common.response.ErrorCode;
import com.vip.common.response.Result;
import com.vip.common.response.Results;
import com.vip.common.util.EmptyUtils;
import com.vip.workflow.dto.TaskDTO;
import com.vip.workflow.service.IFlowTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 任务管理 Service实现类
 *
 * @author wgb
 * @date 2020/5/8 9:32
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FlowTaskServiceImpl implements IFlowTaskService {

    private final TaskService taskService;
    private final RepositoryService repositoryService;
    private final IdentityService identityService;
    private final RuntimeService runtimeService;

    @Override
    public Result<List<TaskDTO>> getBackLogTask() {
        try {
            List<Task> tasks = taskService.createTaskQuery().list();
            List<TaskDTO> result = new ArrayList<>();
            for (Task task : tasks) {
                result.add(new TaskDTO(task));
            }
            return Results.newSuccessResult(result, "查询成功");
        } catch (Exception e) {
            log.error("获取待办事项出错", e);
        }
        return Results.newFailResult(ErrorCode.WORKFLOW_ERROR, "查询失败");
    }

    @Override
    public Result<String> startWorkFlow(String processDefinitionId, String businessId, String userId, Map<String, Object> vars) {
        try {
            // 设置流程发起人
            identityService.setAuthenticatedUserId(userId);
            // 启动流程
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, businessId, vars);
            return Results.newSuccessResult(processInstance.getId(), "发布成功");
        } catch (Exception e) {
            log.error("从流程发布新任务出错", e);
        }
        return Results.newFailResult(ErrorCode.WORKFLOW_ERROR, "发布失败");
    }

    @Override
    public Result<String> completeCurrTask(String taskId, Map<String, Object> vars) {
        try {
            List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskId);
            Object userId = vars.get("userId");
            for (IdentityLink identityLink : identityLinksForTask) {
                if (EmptyUtils.isEmpty(identityLink.getGroupId())) {
                    continue;
                }
                if (userId == null) {
                    return Results.newFailResult(ErrorCode.INVALID_PARAMETER, "参数异常：用户ID不能为空");
                }
                // 查询组的用户
                List<User> usersInGroup = identityService.createUserQuery().memberOfGroup(identityLink.getGroupId()).list();
                if (CollectionUtils.isEmpty(usersInGroup)) {
                    continue;
                }
                // 如果用户不存在则抛出异常
                List<User> has = usersInGroup.stream().filter(x -> x.getId().equals(vars.get("userId").toString())).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(has)) {
                    return Results.newFailResult(ErrorCode.INVALID_PARAMETER, "该用户无流程处理权限");
                }
            }

            taskService.complete(taskId, vars);
            return Results.newSuccessResult(null, "执行成功");
        } catch (Exception e) {
            log.error("完成当前节点任务出错", e);
        }
        return Results.newFailResult(ErrorCode.WORKFLOW_ERROR, "执行失败");
    }

    @Override
    public Result<String> closeCurrTask(String taskId) {
        try {
            // 获取任务信息
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            // 删除任务所在的流程实例ID
            runtimeService.deleteProcessInstance(task.getProcessInstanceId(), "关闭流程");
            return Results.newSuccessResult(null, "流程关闭成功");
        } catch (Exception e) {
            log.error("关闭工作流出错", e);
        }
        return Results.newFailResult(ErrorCode.WORKFLOW_ERROR, "关闭流程失败");
    }

    @Override
    public InputStream getTaskTrackPhoto(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        // ID 为 流程定义Key
        Process process = bpmnModel.getProcessById(processDefinition.getKey());
        // 流程节点ID
        FlowElement flowElement = process.getFlowElement(task.getTaskDefinitionKey());
        DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
        List<String> highLightedActivities = new ArrayList<>();
        highLightedActivities.add(flowElement.getId());
        // 生成图片
        return generator.generateDiagram(bpmnModel, "jpg", highLightedActivities, Collections.emptyList(), "宋体", "宋体", "宋体", null, 2.0);
    }

    @Override
    public Result<String> closeTaskMulti(List<String> taskIds) {
        try {
            for (String taskId : taskIds) {
                // 获取任务信息
                Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
                // 删除任务所在的流程实例ID
                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), "关闭流程");
            }
            return Results.newSuccessResult(null, "关闭成功");
        } catch (Exception e) {
            log.error("批量关闭工作流出错", e);
        }
        return Results.newFailResult(ErrorCode.WORKFLOW_ERROR, "关闭失败");
    }
}
